#include "../include/newfs.h"

struct nfs_super      nfs_super; 
struct custom_options nfs_options;

char* nfs_get_fname(const char* path) {
    char ch = '/';
    char *q = strrchr(path, ch) + 1;
    return q;
}

int nfs_calc_lvl(const char * path) {
    char* str = path;
    int   lvl = 0;
    if (strcmp(path, "/") == 0) {
        return lvl;
    }
    while (*str != NULL) {
        if (*str == '/') {
            lvl++;
        }
        str++;
    }
    return lvl;
}

int nfs_driver_read(int offset, uint8_t *out_content, int size) {
    int      offset_aligned = NFS_ROUND_DOWN(offset, NFS_IO_SZ());
    int      bias           = offset - offset_aligned;
    int      size_aligned   = NFS_ROUND_UP((size + bias), NFS_IO_SZ());
    uint8_t* temp_content   = (uint8_t*)malloc(size_aligned);
    uint8_t* cur            = temp_content;
    ddriver_seek(NFS_DRIVER(), offset_aligned, SEEK_SET);
    while (size_aligned != 0)
    {
        ddriver_read(NFS_DRIVER(), cur, NFS_IO_SZ());
        cur          += NFS_IO_SZ();
        size_aligned -= NFS_IO_SZ();   
    }
    memcpy(out_content, temp_content + bias, size);
    free(temp_content);
    return NFS_ERROR_NONE;
}

int nfs_driver_write(int offset, uint8_t *in_content, int size) {
    int      offset_aligned = NFS_ROUND_DOWN(offset, NFS_BLK_SZ());
    int      bias           = offset - offset_aligned;
    int      size_aligned   = NFS_ROUND_UP((size + bias), NFS_BLK_SZ());
    uint8_t* temp_content   = (uint8_t*)malloc(size_aligned);
    uint8_t* cur            = temp_content;
    nfs_driver_read(offset_aligned, temp_content, size_aligned);
    memcpy(temp_content + bias, in_content, size);
    
    ddriver_seek(NFS_DRIVER(), offset_aligned, SEEK_SET);
    while (size_aligned != 0)
    {
        ddriver_write(NFS_DRIVER(), cur, NFS_IO_SZ());
        cur          += NFS_IO_SZ();
        size_aligned -= NFS_IO_SZ();   
    }

    free(temp_content);
    return NFS_ERROR_NONE;
}

int nfs_alloc_dentry(struct nfs_inode* inode, struct nfs_dentry* dentry, int judge) {
    if (inode->dentrys == NULL) {
        inode->dentrys = dentry;
    }
    else {
        dentry->brother = inode->dentrys;
        inode->dentrys = dentry;
    }
    inode->dir_cnt++;

    int cur_blk = inode->dir_cnt / NFS_DENTRY_PER_DATABLK();    // 当前访问的inode的dentry所处数据块。
    if(judge == 1){
        if(inode->dir_cnt % NFS_DENTRY_PER_DATABLK() == 1){ //是一个数据块的起始dentry。
            int i = 0; 
            int j = 0;
            int blk_id  = 0; 
            int is_find = 0;

            for (i = 0; i < NFS_BLKS_SZ(nfs_super.map_data_blks); i++) {//遍历数据块位图
                for (j = 0; j < 8; j++) {//一字节8位
                    if((nfs_super.map_data[i] & (1 << j)) == 0) {    
                        nfs_super.map_data[i] |= 1 << j; 
                        inode->block_pointer[cur_blk] = blk_id;
                        is_find = 1;
                        break;
                    }
                    blk_id++;
                }
                if (is_find) {
                    break;
                }
            }

            if (!is_find || blk_id == nfs_super.max_data)
                return -NFS_ERROR_NOSPACE;
        }
    }
    
    return inode->dir_cnt;
}


struct nfs_inode* nfs_alloc_inode(struct nfs_dentry * dentry) {
    struct nfs_inode* inode;
    int i = 0; 
    int j = 0;
    int ino_id  = 0; 
    int is_find = 0;

    
    for (i = 0; i < NFS_BLKS_SZ(nfs_super.map_inode_blks); i++) {
        for (j = 0; j < 8; j++) {
            if((nfs_super.map_inode[i] & (1 << j)) == 0) {    
                nfs_super.map_inode[i] |= 1 << j;
                is_find = 1;           
                break;
            }
            ino_id++;
        } if (is_find) {
            break;
        }
    }

    
    if (!is_find || ino_id == nfs_super.max_ino)
        return -NFS_ERROR_NOSPACE;

    inode = (struct nfs_inode*)malloc(sizeof(struct nfs_inode));
    inode->ino  = ino_id; 
    inode->size = 0;
    inode->dir_cnt = 0;
    inode->dentrys = NULL;
    
    dentry->inode = inode;
    dentry->ino   = inode->ino;
    
    inode->dentry = dentry;
    

    if (NFS_IS_REG(inode)) {
        for(int i=0; i<NFS_DATA_PER_FILE; i++) {
            inode->data[i] = (uint8_t *)malloc(NFS_BLK_SZ());
            inode->block_pointer[i] = 0;
        }
    }

    return inode;
}

int nfs_sync_inode(struct nfs_inode * inode) {
    struct nfs_inode_d  inode_d;
    struct nfs_dentry*  dentry_cursor;
    struct nfs_dentry_d dentry_d;
    int offset;
    int ino             = inode->ino;

    inode_d.ino         = ino;
    inode_d.size        = inode->size;
    inode_d.ftype       = inode->dentry->ftype;
    inode_d.dir_cnt     = inode->dir_cnt;
    for(int i=0; i<NFS_DATA_PER_FILE; i++) {
        inode_d.block_pointer[i] = inode->block_pointer[i];
    }
    
    if (nfs_driver_write(NFS_INO_OFS(ino), (uint8_t *)&inode_d, 
                     sizeof(struct nfs_inode_d)) != NFS_ERROR_NONE) {
        NFS_DBG("[%s] io error\n", __func__);
        return -NFS_ERROR_IO;
    }

    if (NFS_IS_DIR(inode)) {    
        
        int blk_number = 0;                      
        dentry_cursor = inode->dentrys;

        while(dentry_cursor != NULL && blk_number < NFS_DATA_PER_FILE){
            offset = NFS_DATA_OFS(inode->block_pointer[blk_number]);
            while ((dentry_cursor != NULL) && (offset < NFS_DATA_OFS(inode->block_pointer[blk_number] + 1)))
            {
                memcpy(dentry_d.fname, dentry_cursor->fname, NFS_MAX_FILE_NAME);
                dentry_d.ftype = dentry_cursor->ftype;
                dentry_d.ino = dentry_cursor->ino;
                if (nfs_driver_write(offset, (uint8_t *)&dentry_d, sizeof(struct nfs_dentry_d)) != NFS_ERROR_NONE) {
                    NFS_DBG("[%s] io error\n", __func__);
                    return -NFS_ERROR_IO;                     
                }
                
                if (dentry_cursor->inode != NULL) {
                    nfs_sync_inode(dentry_cursor->inode);
                }

                dentry_cursor = dentry_cursor->brother;
                offset += sizeof(struct nfs_dentry_d);
            }
            blk_number++;
        }
    }
    else if (NFS_IS_REG(inode)) {
        for(int i=0; i<NFS_DATA_PER_FILE; i++){
            if (inode->block_pointer[i] == 0) continue;
            if (nfs_driver_write(NFS_DATA_OFS(inode->block_pointer[i]), inode->data[i], NFS_BLK_SZ()) != NFS_ERROR_NONE) {
                NFS_DBG("[%s] io error\n", __func__);
                return -NFS_ERROR_IO;
            }
        }
    }
    return NFS_ERROR_NONE;
}

struct nfs_inode* nfs_read_inode(struct nfs_dentry * dentry, int ino) {
    struct nfs_inode* inode = (struct nfs_inode*)malloc(sizeof(struct nfs_inode));
    struct nfs_inode_d inode_d;
    struct nfs_dentry* sub_dentry;
    struct nfs_dentry_d dentry_d;
    int    dir_cnt = 0;

    /* 从磁盘中读取ino对应的inode_d */
    if (nfs_driver_read(NFS_INO_OFS(ino), (uint8_t *)&inode_d, 
                        sizeof(struct nfs_inode_d)) != NFS_ERROR_NONE) {
        NFS_DBG("[%s] io error\n", __func__);
        return NULL;                    
    }

    /* 根据inode_d更新内存中inode参数 */
    inode->dir_cnt = 0;
    inode->ino = inode_d.ino;
    inode->size = inode_d.size;
    inode->dentry = dentry;
    inode->dentrys = NULL;
    for(int i = 0; i < NFS_DATA_PER_FILE; i++){
        inode->block_pointer[i] = inode_d.block_pointer[i];
    }

    /*如果inode是目录类型，则需要读取每一个目录项并建立连接*/
    if (NFS_IS_DIR(inode)) {
        dir_cnt = inode_d.dir_cnt;
        int blk_number = 0;
        int offset;

        /*处理每一个目录项*/
        while(dir_cnt > 0 && blk_number < NFS_DATA_PER_FILE){
            offset = NFS_DATA_OFS(inode->block_pointer[blk_number]);

            // 当从磁盘读入时，由于磁盘中没有链表指针，因此只能通过一个dentry_d大小来进行遍历
            while((dir_cnt > 0) && (offset + sizeof(struct nfs_dentry_d) < NFS_DATA_OFS(inode->block_pointer[blk_number] + 1))){
                if (nfs_driver_read(offset, (uint8_t *)&dentry_d, sizeof(struct nfs_dentry_d)) != NFS_ERROR_NONE){
                    NFS_DBG("[%s] io error\n", __func__);
                    return NULL;  
                }
                
                /* 用从磁盘中读出的dentry_d更新内存中的sub_dentry */
                sub_dentry = new_dentry(dentry_d.fname, dentry_d.ftype);
                sub_dentry->parent = inode->dentry;
                sub_dentry->ino    = dentry_d.ino; 
                nfs_alloc_dentry(inode, sub_dentry, 0);

                offset += sizeof(struct nfs_dentry_d);
                dir_cnt--;
            }
            blk_number++;
        }
    }
    /*如果inode是文件类型，则直接读取数据即可*/
    else if (NFS_IS_REG(inode)) {
        for (int i = 0; i < NFS_DATA_PER_FILE; i++){
            inode->data[i] = (uint8_t *)malloc(NFS_BLK_SZ());
            if (inode->block_pointer[i] == 0) continue;
            if (nfs_driver_read(NFS_DATA_OFS(inode->block_pointer[i]), (uint8_t *)inode->data[i], 
                                NFS_BLK_SZ()) != NFS_ERROR_NONE) {
                NFS_DBG("[%s] io error\n", __func__);
                return NULL;                    
            }
        }
    }

    return inode;
}

struct nfs_dentry* nfs_get_dentry(struct nfs_inode * inode, int dir) {
    struct nfs_dentry* dentry_cursor = inode->dentrys;
    int    cnt = 0;
    while (dentry_cursor)
    {
        if (dir == cnt) {
            return dentry_cursor;
        }
        cnt++;
        dentry_cursor = dentry_cursor->brother;
    }
    return NULL;
}

struct nfs_dentry* nfs_lookup(const char * path, int* is_find, int* is_root) {
    struct nfs_dentry* dentry_cursor = nfs_super.root_dentry;
    struct nfs_dentry* dentry_ret = NULL;
    struct nfs_inode*  inode; 
    int   total_lvl = nfs_calc_lvl(path);
    int   lvl = 0;
    int   is_hit;
    char* fname = NULL;
    char* path_cpy = (char*)malloc(sizeof(path));
    *is_root = 0;
    strcpy(path_cpy, path);

    /* 如果路径的级数为0，则说明是根目录，直接返回根目录项即可 */
    if (total_lvl == 0) {                           
        *is_find = 1;
        *is_root = 1;
        dentry_ret = nfs_super.root_dentry;
    }

    /* 获取最外层文件夹名称 */
    fname = strtok(path_cpy, "/");       
   
    while (fname)
    {   
        lvl++;
        // NFS_DBG("[%s] [%d] \n", fname, lvl);
        /* Cache机制，如果当前dentry对应的inode为空，则从磁盘中读取 */
        if (dentry_cursor->inode == NULL) {           
            // NFS_DBG("?[%s] [%d] \n", fname, lvl);
            nfs_read_inode(dentry_cursor, dentry_cursor->ino);
        }

        /* 当前dentry对应的inode */
        inode = dentry_cursor->inode;

        /* 若当前inode对应文件类型，且还没查找到对应层数，说明路径错误，跳出循环 */
        if (NFS_IS_REG(inode) && lvl < total_lvl) {
            NFS_DBG("[%s] not a dir\n", __func__);
            dentry_ret = inode->dentry;
            break;
        }

        if (NFS_IS_DIR(inode)) {
            dentry_cursor = inode->dentrys;
            is_hit        = 0;

            while (dentry_cursor) {
                if (memcmp(dentry_cursor->fname, fname, strlen(fname)) == 0) {
                    is_hit = 1;
                    break;
                }
                dentry_cursor = dentry_cursor->brother;
            }
            
            if (!is_hit) {
                *is_find = 0;
                NFS_DBG("[%s] not found %s\n", __func__, fname);
                dentry_ret = inode->dentry;
                break;
            }

            if (is_hit && lvl == total_lvl) {
                *is_find = 1;
                dentry_ret = dentry_cursor;
                break;
            }
        }
        fname = strtok(NULL, "/"); 
    }

    if (dentry_ret->inode == NULL) {
        // NFS_DBG("?[%s] [%d] \n", fname, lvl);
        dentry_ret->inode = nfs_read_inode(dentry_ret, dentry_ret->ino);
    }
    
    return dentry_ret;
}

int nfs_mount(struct custom_options options){
    int                 ret = NFS_ERROR_NONE;
    int                 driver_fd;
    struct nfs_super_d  nfs_super_d; 
    struct nfs_dentry*  root_dentry;
    struct nfs_inode*   root_inode;

    int                 inode_num;
    int                 map_inode_blks;

    int                 data_num;
    int                 map_data_blks;
    
    int                 super_blks;
    int                 is_init = 0;

    nfs_super.is_mounted = 0;

    driver_fd = ddriver_open(options.device);

    if (driver_fd < 0) {
        return driver_fd;
    }

    // 向超级块中写入相关信息
    nfs_super.fd = driver_fd;
    ddriver_ioctl(NFS_DRIVER(), IOC_REQ_DEVICE_SIZE,  &nfs_super.sz_disk);
    ddriver_ioctl(NFS_DRIVER(), IOC_REQ_DEVICE_IO_SZ, &nfs_super.sz_io);
    nfs_super.sz_blks = 2 * nfs_super.sz_io;  
    
    // 创建根目录
    root_dentry = new_dentry("/", NFS_DIR);

    // 读取磁盘超级块nfs_super_d到内存。
    if (nfs_driver_read(NFS_SUPER_OFS, (uint8_t *)(&nfs_super_d), sizeof(struct nfs_super_d)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }   
    
    // 根据超级块幻数判断是否为第一次启动磁盘，如果是第一次启动磁盘，则需要建立磁盘超级块的布局。
    // 读取super
    if (nfs_super_d.magic_num != NFS_MAGIC_NUM) {     /* 幻数无 */
        /* 估算各部分大小 */
        /* 计算过程位于types.h中 */
        super_blks = NFS_SUPER_BLKS;
        inode_num  = NFS_INODE_BLKS;
        data_num = NFS_DATA_BLKS;
        map_inode_blks = NFS_MAP_INODE_BLKS;
        map_data_blks = NFS_MAP_DATA_BLKS;

        /* 布局layout */
        nfs_super.max_ino = inode_num;
        nfs_super.max_data = data_num;

        nfs_super_d.map_inode_blks = map_inode_blks; 
        nfs_super_d.map_data_blks = map_data_blks; 

        nfs_super_d.map_inode_offset = NFS_SUPER_OFS + NFS_BLKS_SZ(super_blks);
        nfs_super_d.map_data_offset = nfs_super_d.map_inode_offset + NFS_BLKS_SZ(map_inode_blks);

        nfs_super_d.inode_offset = nfs_super_d.map_data_offset + NFS_BLKS_SZ(map_data_blks);
        nfs_super_d.data_offset = nfs_super_d.inode_offset + NFS_BLKS_SZ(inode_num);

        nfs_super_d.sz_usage = 0;
        nfs_super_d.magic_num = NFS_MAGIC_NUM;

        is_init = 1;
    }

    /* 建立 in-memory 结构 */
    // 初始化超级块
    nfs_super.sz_usage   = nfs_super_d.sz_usage; 

    // 建立inode位图    
    nfs_super.map_inode = (uint8_t *)malloc(NFS_BLKS_SZ(nfs_super_d.map_inode_blks));
    nfs_super.map_inode_blks = nfs_super_d.map_inode_blks;
    nfs_super.map_inode_offset = nfs_super_d.map_inode_offset;
    nfs_super.inode_offset = nfs_super_d.inode_offset;

    // 建立数据块位图
    nfs_super.map_data = (uint8_t *)malloc(NFS_BLKS_SZ(nfs_super_d.map_data_blks));
    nfs_super.map_data_blks = nfs_super_d.map_data_blks;
    nfs_super.map_data_offset = nfs_super_d.map_data_offset;
    nfs_super.data_offset = nfs_super_d.data_offset;

    if (nfs_driver_read(nfs_super_d.map_inode_offset, (uint8_t *)(nfs_super.map_inode), 
                        NFS_BLKS_SZ(nfs_super_d.map_inode_blks)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }

    if (nfs_driver_read(nfs_super_d.map_data_offset, (uint8_t *)(nfs_super.map_data), 
                        NFS_BLKS_SZ(nfs_super_d.map_data_blks)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }

    if (is_init) {                                    /* 分配根节点 */
        root_inode = nfs_alloc_inode(root_dentry);
        nfs_sync_inode(root_inode);
    }
    
    root_inode            = nfs_read_inode(root_dentry, NFS_ROOT_INO);
    root_dentry->inode    = root_inode;
    nfs_super.root_dentry = root_dentry;
    nfs_super.is_mounted  = 1;

    return ret;
}
/**
 * @brief 卸载nfs
 * 
 * @return int 
 */
int nfs_umount() {
    struct nfs_super_d  nfs_super_d; 

    if (!nfs_super.is_mounted) {
        return NFS_ERROR_NONE;
    }

    nfs_sync_inode(nfs_super.root_dentry->inode);     /* 从根节点向下刷写节点 */

    /* 用内存中的超级块nfs_super更新即将写回磁盘的nfs_super_d */                                    
    nfs_super_d.magic_num           = NFS_MAGIC_NUM;
    nfs_super_d.sz_usage            = nfs_super.sz_usage;

    nfs_super_d.map_inode_blks      = nfs_super.map_inode_blks;
    nfs_super_d.map_inode_offset    = nfs_super.map_inode_offset;
    nfs_super_d.inode_offset        = nfs_super.inode_offset;

    nfs_super_d.map_data_blks       = nfs_super.map_data_blks;
    nfs_super_d.map_data_offset     = nfs_super.map_data_offset;
    nfs_super_d.data_offset         = nfs_super.data_offset;
    
    /* 将超级块刷回磁盘 */
    if (nfs_driver_write(NFS_SUPER_OFS, (uint8_t *)&nfs_super_d, 
                     sizeof(struct nfs_super_d)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }

    /* 将inode位图刷回磁盘 */
    if (nfs_driver_write(nfs_super_d.map_inode_offset, (uint8_t *)(nfs_super.map_inode), 
                         NFS_BLKS_SZ(nfs_super_d.map_inode_blks)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }

    /* 将data位图刷回磁盘 */
    if (nfs_driver_write(nfs_super_d.map_data_offset, (uint8_t *)(nfs_super.map_data), 
                         NFS_BLKS_SZ(nfs_super_d.map_data_blks)) != NFS_ERROR_NONE) {
        return -NFS_ERROR_IO;
    }

    /* 释放内存中的inode位图和data位图 */
    free(nfs_super.map_inode);
    free(nfs_super.map_data);

    /* 关闭驱动 */
    ddriver_close(NFS_DRIVER());

    return NFS_ERROR_NONE;
}